import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvFileSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;

import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import static java.lang.Thread.sleep;

/**
 * 继承 InitAndEnd，使得每一个浏览器都能有一个驱动
 * TestMethodOrder 指定执行的顺序，按照 order 的顺序执行
 *
 * 注意：：：测试用例 5中测试 文章详情页，测试用例 6中测试 写博客功能
 * 这里的文章第一篇是 ”祝你好运 “，如果新增博客的话，在后面测试过程中传入的参数也需要跟着改变，所以这里为了不改变传入的参数
 * 就规定第一篇为 ”祝你好运 “，方便测试。在后边中，新增的 “study”文章用来测试新增博客的功能
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class blogSsmCases extends InitAndEnd{

    public static Stream<Arguments> Generator() {
        return Stream.of(Arguments.arguments("http://localhost:8080/blog_content.html?id=",
                "博客正文", "祝你好运"));
    }

    /**
     * 测试用例 1：登录测试：登录成功
     * 输入正确的账号、密码，才能登陆成功。因为验证码随机生成，所以屏蔽掉了验证码
     */
    @Order(2)
    @ParameterizedTest
    @CsvFileSource(resources = "LoginSuccess.csv")
     void LoginSuccess(String username, String password, String myblog_list_url) throws InterruptedException {
//        System.out.println(username + password + myblog_list_url);
        // 1.打开博客登录页面
        webDriver.get("http://localhost:8080/login.html");
        sleep(300); // 显示等待
        // 隐式等待 3 s
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 2.输入账号 sy
        webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 3.输入密码 123
        webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 4.点击登录
        webDriver.findElement(By.cssSelector("#submit")).click();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 5.跳转到我的个人博客列表 --- 获取到当前页面的url，如果等于目标url，则成功，否则跳转失败
        String cur_url = webDriver.getCurrentUrl();
        Assertions.assertEquals(myblog_list_url, cur_url);
        sleep(300);

        // 6.我的博客列表页展示的用户信息是"sy"，当做验证条件
        String cur_username = webDriver.findElement(By.cssSelector
                ("body > div.container > div.container-left > div > h3")).getText();
        Assertions.assertEquals(username, cur_username);
    }

    /**
     * 测试用例 2： 登陆失败
     * 输入账号密码错误之后，页面还是会在登录页面，不跳转，所以用这个点来验证失败
     */
    @Order(1)
    @Test
    void LoginFail() {
        webDriver.get("http://localhost:8080/login.html");

        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        webDriver.findElement(By.cssSelector("#username")).sendKeys("1");
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        webDriver.findElement(By.cssSelector("#password")).sendKeys("123");
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        webDriver.findElement(By.cssSelector("#submit")).click();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 切换到 alert 弹窗上，accept()：点击确认按钮，点击确认之后才能获取到当前页面url
        webDriver.switchTo().alert().accept();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        String cur_url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://localhost:8080/login.html", cur_url);
    }

    /**
     * 测试用例 3：我的个人博客列表页的测试
     * 通过判断列表页的博客数量不为 0，即可判断
     */
    @Order(3)
    @Test
    void MyBlogList() {
        // 1. 打开博客列表页
        webDriver.get("http://localhost:8080/myblog_list.html");

        // 2. 获取到页面上所有博客标题对应的元素，找到的是一批元素，所以 findElements
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        int title_num = webDriver.findElements(By.cssSelector(".title")).size();

        // 3. 如果元素的数量不为0，测试通过
        Assertions.assertNotEquals(0, title_num);
    }

    /**
     * 测试用例 4：博客主页的测试
     * 判断主页博客的数量不为 0，并且可以找到翻页的按钮，一共有 4个，判断数量为 4
     */
    @Order(4)
    @Test
    void BlogList(){
        // 1. 打开博客列表页
        webDriver.get("http://localhost:8080/blog_list.html");

        // 2. 获取到页面上所有博客标题对应的元素，找到的是一批元素，所以 findElements
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        int title_num = webDriver.findElements(By.cssSelector(".title")).size();
        int button_num = webDriver.findElements(By.cssSelector(".blog-pagnation-item")).size();

        // 3. 如果元素的数量不为0，测试通过
        Assertions.assertNotEquals(0, title_num);
        Assertions.assertEquals(4, button_num);
    }

    /**
     * 测试用例 5：博客详情页的测试
     * 通过方法传参
     */
    @Order(5)
    @ParameterizedTest
    @MethodSource("Generator")
    void BlogDetail(String expected_url, String expected_title, String expected_blog_title) {
//        webDriver.get("http://localhost:8080/myblog_list.html");
        // 1. 找到第一篇博客的“查看全文”按钮，并点击
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        webDriver.findElement(By.xpath("//*[@id=\"artlist\"]/div[1]/a[1]")).click();
        // 2. 获取当前页面的 url --- 此时是没有窗口切换的，它是在一个页面的，
        // 窗口切换是指重新开启了一个新窗口才是窗口的切换
        String cur_url = webDriver.getCurrentUrl();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 3. 获取当前页面的title
        String cur_title = webDriver.getTitle();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 4. 获取博客标题，获取标题的文本
        String blog_title = webDriver.findElement(By.xpath("//*[@id=\"title\"]")).getText();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 5. 校验
//        Assertions.assertEquals(expected_url, cur_url);
        // 方法中传入的 expected_url 不同给 id 传参，因为上边的测试用例会新增博客，每次增加的博客 id 都会有变化
        if(cur_url.contains(expected_url)) {
            System.out.println("测试通过");
        } else {
            System.out.println("测试不通过");
        }
        Assertions.assertEquals(expected_title, cur_title);
        Assertions.assertEquals(expected_blog_title, blog_title);
    }

    /**
     * 测试用例 6：写博客功能的测试
     * 写完博客发布时会出现弹框（询问是否继续添加文章）点击确定，会刷新当前页面（依旧在博客编辑页面），
     * 单击取消会返回到 个人博客页面
     */
    @Order(6)
    @Test
    void EditBlog() throws InterruptedException {
        // 1. 找到写博客按钮，点击
        webDriver.findElement(By.cssSelector("#userElement > a:nth-child(1)")).click();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 2. 找到输入框，输入标题（不采用这个方式）
        // 通过 js 将标题输入 （采取这个方式）
        ((JavascriptExecutor)webDriver).executeScript(
                "document.getElementById(\"title\").value=\"study\"");
        sleep(1000);
        // 3. 点击发布
        webDriver.findElement(By.cssSelector("body > div.blog-edit-container > div.title > button")).click();
        sleep(1000);

        // 4.1 获取当前 url，校验页面跳转是否正确。点击确定添加文章，url仍然是编辑页的
        webDriver.switchTo().alert().accept();
        String cur_url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://localhost:8080/blog_add.html", cur_url);
        // 4.2 获取当前 url，校验页面跳转是否正确。点击取消添加文章，页面跳转到个人博客列表页
//        webDriver.switchTo().alert().dismiss();
//        String cur_url = webDriver.getCurrentUrl();
//        Assertions.assertEquals("http://localhost:8080/myblog_list.html", cur_url);
    }

    /**
     * 测试用例 7：发布博客之后进行校验
     * 验证新博客的 标题以及时间 是否正确
     */
    @Order(7)
    @Test
    void BlogInfoChecked() {
        webDriver.get("http://localhost:8080/myblog_list.html");
        // 1. 获取到第一篇博客标题
        String first_blog_title = webDriver.findElement(
                By.cssSelector("#artlist > div:nth-child(1) > div.title")).getText();
        // 2. 获取第一篇博客发布时间
        String first_blog_time = webDriver.findElement(
                By.xpath("//*[@id=\"artlist\"]/div[1]/div[2]")).getText();
        // 3. 校验标题和时间是否正确
        Assertions.assertEquals("study", first_blog_title);
        if(first_blog_time.contains("2023-09-03")){
            System.out.println("测试通过");
        } else {
            System.out.println("测试未通过");
        }
    }

    /**
     * 测试用例 8：删除博客功能
     * 点击删除，出现是否确认删除的弹框，然后通过查看当前第一篇文章的标题来判断是否删除成功
     */
    @Order(8)
    @Test
    void DelBlog() {
        // 1. 打开博客列表页面
        webDriver.get("http://localhost:8080/myblog_list.html");
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 2. 找到删除按钮并点击点击删除按钮
        webDriver.findElement(By.cssSelector
                ("#artlist > div:nth-child(1) > a:nth-child(6)")).click();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 3.1 点击取消删除按钮，判断当前标题如果是"study"，那么测试成功
//        webDriver.switchTo().alert().dismiss();
//        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//        String cur_title = webDriver.findElement(By.cssSelector
//                ("#artlist > div:nth-child(1) > div.title")).getText();
//        Assertions.assertEquals("study", cur_title);

        // 3.2 点击弹框中的“确认”
        webDriver.switchTo().alert().accept();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 判断当前第一个文章的标题是不是“祝你好运”，如果是那么删除成功
        String cur_title = webDriver.findElement(By.cssSelector
                ("#artlist > div:nth-child(1) > div.title")).getText();
        Assertions.assertEquals("祝你好运", cur_title);
    }

    /**
     * 测试用例 9：注销功能
     */
    @Order(9)
    @Test
    void Logout() {
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)")).click();
        webDriver.switchTo().alert().accept();
        // 校验url，回到了博客主页
        String cur_url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://localhost:8080/blog_list.html", cur_url);
    }

}
